#pragma once
#include "socket.hpp"

#include <sys/epoll.h>
#include <string>
#include <unordered_map>


#define BACKLOG 5
#define SIZE 256
#define MAXNUM 64

namespace ns_epoll {

    class Reactor; 
    class EventItem;

    typedef int(*callback_t)(EventItem*);

    //当成结构体使用
    class EventItem {
    public:
        //与通信相关
        int sock;

        //回指Reactor
        Reactor* R;

        //有关数据处理的回调函数，用来进行逻辑解耦！  应用数据就绪等通信细节和数据的处理模块使用该方法进行解耦！
        callback_t recv_handler;
        callback_t send_handler;
        callback_t error_handler; 

        std::string inbuffer; //读取到的数据缓冲区
        std::string outbuffer;//待发送的数据缓冲区
    public:
        EventItem() :sock(0), R(nullptr), recv_handler(nullptr), send_handler(nullptr), error_handler(nullptr) {}
        
        //管理回调
        void ManagerCallBack(callback_t _recv,callback_t _send,callback_t _err) {
            recv_handler = _recv;
            send_handler = _send;
            error_handler = _err;
        }

        ~EventItem() {
            //TODO
        }

    };

    class Reactor {
    private:
        int epfd;

        std::unordered_map<int, EventItem> event_item; //sock:EventItem

    public:
        Reactor() :epfd(-1) {}

    public:
        void InitReactor() {
            
            //创建epoll模型
            if ((epfd = epoll_create(SIZE)) < 0) {
                std::cerr << "epoll_creat error!!" << std::endl;
                exit(4);
            }
            std::cout << "server start" << std::endl;
        }


        //事件分派器
        void Distatch(int timeout) {
            //如果底层事件就绪，就把对应的事件分派给指定的回调函数进行统一处理
            
            struct epoll_event revs[MAXNUM];

            //返回值num表示就绪的事件数，内核会将就绪事件依次放入revs中
            int num = epoll_wait(epfd, revs, MAXNUM, timeout);

            for (int i = 0; i < num; ++i) {
                int sock = revs[i].data.fd;
                uint32_t mask = revs[i].events;

                
                //把所有的异常事件统一交给read，write处理
                //if ((revs[i].events & EPOLLERR || revs[i].events & EPOLLHUP)) mask | (EPOLLIN | EPOLLOUT);
                //异常事件发生 或者对端关闭
                if (revs[i].events & EPOLLERR || revs[i].events & EPOLLHUP) {
                    //如果error_handler被设置，就直接调用
                    if (event_item[sock].error_handler) event_item[sock].error_handler(&event_item[sock]);
                }
                //读事件发生
                if (revs[i].events & EPOLLIN) {
                    //如果recv_handler被设置，就直接调用 
                    if (event_item[sock].recv_handler) event_item[sock].recv_handler(&event_item[sock]);
                }
                //写事件发生
                if (revs[i].events & EPOLLOUT) {
                    //如果send_handler被设置，就直接调用
                    if (event_item[sock].send_handler) event_item[sock].send_handler(&event_item[sock]);
                }   

            }
        }

        bool AddEvent(int sock, int event, const EventItem& item) {
            struct epoll_event ev;
            ev.events = 0;
            ev.events |= event;
            ev.data.fd = sock;
            if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
                std::cerr << "epoll_ctr error  fd:" << sock << std::endl;
                return false;
            }

            event_item.insert({ sock,item });

            std::cout << "debug  添加 :" << sock << " 到epoller中，成功" << std::endl;
            return true;
        }
        bool DelEvent(int sock) {
            if (epoll_ctl(epfd, EPOLL_CTL_DEL, sock, nullptr) < 0) {
                std::cerr << "epoll_ctl error  fd:" << sock << std::endl;
                return false;
            }

            event_item.erase(sock);
            return true;
        }

        //
        void EnableReadWrite(int sock,bool read,bool write) {
            struct epoll_event evt;
            evt.data.fd = sock;
            evt.events = (read ? EPOLLIN : 0) | (write ? EPOLLOUT : 0) | EPOLLET;
            if (epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &evt)) {
                std::cerr << "epoll_ctl_mod error , fd: " << sock << std::endl;
            }
        }

        ~Reactor() {
            if (epfd >= 0) close(epfd);
        }
    };
}


